## Script (Python) "assessmentexplorer_modelreport"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##title=Assessment Explorer (by Models)
##parameters=

#####################################################################
# Product:      KnowledgeEngine (Plone Edition)
#
# File:         assessmentexplorer_modelreport.py
#
# Copyright:    Copyright (c) 2005, Faulkner Technologies
#
# Author:       Brian Oliver
#
# Description:  A python script to control/handle requests from the
#               assessmentexplorer_modeloptions.pt and
#               assessmentexplorer_modelreport.pt pages
#
#####################################################################

from Products.KnowledgeEngine.AssessmentFilter import AssessmentFilter, decodeAssessmentFilterFromString
from Products.KnowledgeEngine.KERLProcessor import getDependencies

#------------------------
#set the default batch size (the number of assessments to display on each page)
batchSize = 15

#------------------------
#get the request from the context... we will use it to find stuff!
request=context.REQUEST

# Grab the debug method
#debug = context.debug Jamesd 20060623 - This is getting an AttributeError.

#get the session from the request
session = request["SESSION"]

#------------------------
#get the sercurity, user provider, assessment storage and credit management services
securityService = context.knowledgeengine_securityservice
userProviderService = context.knowledgeengine_userproviderservice
assessmentStorageService = context.knowledgeengine_assessmentstorageservice
creditManagementService = context.knowledgeengine_creditmanagementservice

#------------------------
#get the knowledge engine user
user = userProviderService.getUser(request["AUTHENTICATED_USER"].getId())

#------------------------
#get the model we are exploring
if request.has_key('modelIdentity'):
    model = assessmentStorageService.getModel(request['modelIdentity'])
else:
    model = assessmentStorageService.getModel(request.form['modelIdentity'])
    
accessModelPermission = securityService.getEffectivePermission('AccessModel', model.getIdentity(), user.getIdentity())

from AccessControl import Unauthorized

if accessModelPermission is None or not accessModelPermission.granted():
    raise Unauthorized("You do not have permission to access this model")
    
    
#------------------------
# Get the report pageAction
#
if request.has_key('pageAction'):
    pageAction = request['pageAction']
else:
    if request.form.has_key('pageAction'):
        pageAction = request.form['pageAction']
    else:
        pageAction = 'NAVIGATE'

#------------------------
#construct a list of assessment filters to display in the explorer
assessmentFilters = []

#get the users permission to 'ExploreAllAssessments'
exploreAllAssessmentsPermission = securityService.getEffectivePermission("ExploreAllAssessments", model.getIdentity(), user.getIdentity())
hasExploreAllAssessmentsPermission = exploreAllAssessmentsPermission is not None and exploreAllAssessmentsPermission.granted()

#add the 'all assessments' filter for the model

noun_plural = model.getNoun_plural()

if hasExploreAllAssessmentsPermission:
    assessmentFilter = AssessmentFilter("All %s" % noun_plural, None, model, exploreAllAssessmentsPermission.getAssessmentScope())
    assessmentFilters.append(assessmentFilter)

#add the 'anonymous assessments' filter for the model
if hasExploreAllAssessmentsPermission:
    assessmentFilter = AssessmentFilter("Anonymous %s" % noun_plural, ['assessment', 'createdby', 'anonymous'], model, exploreAllAssessmentsPermission.getAssessmentScope())
    assessmentFilters.append(assessmentFilter)

#add the 'checked out assessments' filter for the model
if hasExploreAllAssessmentsPermission and not model.getPermitsConcurrentAssessment():
    assessmentFilter = AssessmentFilter("Checked Out %s" % noun_plural, ['assessment', 'ischeckedout'], model, exploreAllAssessmentsPermission.getAssessmentScope())
    assessmentFilters.append(assessmentFilter)

#add the 'orphaned assessments' filter for the model
if hasExploreAllAssessmentsPermission:
    assessmentFilter = AssessmentFilter("Orphaned %s" % noun_plural, ['assessment', 'isorphaned'], model, exploreAllAssessmentsPermission.getAssessmentScope())
    assessmentFilters.append(assessmentFilter)

#add the repository filters
for repository in model.getRepositories():
    #does the user have access to everything?
    if hasExploreAllAssessmentsPermission:
        #use the explore all permission and scope
        assessmentFilter = AssessmentFilter(repository.getTitleOrId(), ['assessment', 'inrepository', repository.getIdentity()], model, exploreAllAssessmentsPermission.getAssessmentScope())
        assessmentFilters.append(assessmentFilter)

    #no.. so check repository level permissions
    else:
        #use the access 
        accessRepositoryPermission = securityService.getEffectivePermission("AccessRepository", repository.getIdentity(), user.getIdentity())
        hasAccessRepositoryPermission = accessRepositoryPermission is not None and accessRepositoryPermission.granted()
        if hasAccessRepositoryPermission:        
            assessmentFilter = AssessmentFilter(repository.getTitleOrId(), ['assessment', 'inrepository', repository.getIdentity()], model, accessRepositoryPermission.getAssessmentScope())
            assessmentFilters.append(assessmentFilter)

#get the first filter (we use this for initialisation in places)
if len(assessmentFilters) > 0:
    firstAssessmentFilter = assessmentFilters[0]
else:
    firstAssessmentFilter = None

#we should use the 'all filter' for new requests
if pageAction == "NEW" and not request.form.has_key('encodedCustomAssessmentFilter'):
    #use the first assessment filter
    currentAssessmentFilter = firstAssessmentFilter

#has a custom filter been provided?
elif request.form.has_key('encodedCustomAssessmentFilter'):
    #decode the assessment filter
    currentAssessmentFilter = decodeAssessmentFilterFromString(request.form['encodedCustomAssessmentFilter'])
   
    #set that the filter is a custom one!
    currentAssessmentFilter.setTitle("Filtered List of Assessments")
    
#is the assessment filter in the session
elif session.has_key('currentAssessmentFilter'):
    currentAssessmentFilter = session.get('currentAssessmentFilter')
    
else:
    #use the first assessment filter
    currentAssessmentFilter = firstAssessmentFilter

#construct a filter map so we can index directly to a filter
assessmentFilterMap = {}
for filter in assessmentFilters:
    assessmentFilterMap[filter.getTitle()] = filter

#------------------------
#get the current batch
if request.has_key('batchNr'):
    batchNr = int(request['batchNr'])    
elif request.form.has_key('batchNr'):
    batchNr = int(request.form['batchNr'])
else:
    batchNr = 0

#get the number of batches
if request.has_key('nrBatches'):
    nrBatches = int(request['nrBatches'])
elif request.form.has_key('nrBatches'):
    nrBatches = int(request.form['nrBatches'])
else:
    nrBatches = 0
    
#------------------------
#get how we are sorting
if request.has_key('sortBy'):
    sortBy = request['sortBy']
elif request.form.has_key('sortBy'):
    sortBy = request.form['sortBy']
else: 
    sortBy = 'instantCreated'

#------------------------------------------------------------------------
# Check is a subFilter has been selected
#------------------------------------------------------------------------
if request.has_key('newSubFilter'):
    subFilter = request['newSubFilter']
else:
    subFilter = None

#------------------------------------------------------------------------
# Check if we're filtering on creation of modification dates
#------------------------------------------------------------------------
if request.has_key('displayCreationDateFilters'):
    displayCreationDateFilters = request['displayCreationDateFilters']
else:
    displayCreationDateFilters = None

if request.has_key('createdAfterDate'):
    createdAfterDate = request['createdAfterDate']
else:
    createdAfterDate = None

if request.has_key('createdBeforeDate'):
    createdBeforeDate = request['createdBeforeDate']
else:
    createdBeforeDate = None



if request.has_key('displayModificationDateFilters'):
    displayModificationDateFilters = request['displayModificationDateFilters']
else:
    displayModificationDateFilters = None

if request.has_key('modifiedAfterDate'):
    modifiedAfterDate = request['modifiedAfterDate']
else:
    modifiedAfterDate = None

if request.has_key('modifiedBeforeDate'):
    modifiedBeforeDate = request['modifiedBeforeDate']
else:
    modifiedBeforeDate = None

#------------------------
#determine the pageAction to initialise the search
if pageAction == 'NEW':
    batchNr = 0
    
elif pageAction == 'NAVIGATE':
    #determine the type of navigation
    if request.form.has_key('btnExplore'):
        #get the new filter to use (if one is specified, otherwise use the first filter in the list of filters)
        if assessmentFilterMap.has_key(request.form['newFilter']):
            currentAssessmentFilter = assessmentFilterMap[request.form['newFilter']]
        elif currentAssessmentFilter.getTitle() != request.form['newFilter']:
            currentAssessmentFilter = firstAssessmentFilter

        #get how we are sorting
        sortBy = request.form['newSortBy']

        #it's a new search!
        batchNr = 0
    
    elif request.form.has_key('btnFirst'):
        batchNr = 0

    elif request.form.has_key('btnBack'):
        batchNr = batchNr - 1

    elif request.form.has_key('btnNext'):
        batchNr = batchNr + 1

    elif request.form.has_key('btnLast'):
        batchNr = nrBatches + 1     #let's go past the last batch - we clean up after the search

    elif request.form.has_key('btnRenameAssessments'):
        #------------------------------------#
        # RENAME ASSESSMENT(s)

        #get permission
        renameAnyAssessmentPermission = securityService.getEffectivePermission('RenameAnyAssessment', model.getIdentity(), user.getIdentity());
       
        #does the user have permission to rename assessment(s)?
        if renameAnyAssessmentPermission is not None and renameAnyAssessmentPermission.granted():

            #build a list of the assessment to be renamed
            assessmentIds = []
            prefix = "txt%s" % (model.getIdentity(),)
            for formKey in request.form.keys():
                if prefix == formKey[0:len(prefix)]:
                    assessmentId = formKey[len(prefix):]
                    originalName = request.form['hid%s%s' % (model.getIdentity(), assessmentId)]
                    newName = request.form['txt%s%s' % (model.getIdentity(), assessmentId)]
                    if originalName != newName:
                        assessmentIds += [assessmentId]
                assessments = [assessmentStorageService.loadAssessment(assessmentId, model) for assessmentId in assessmentIds]

                #rename each of the assessments
                for assessment in assessments:
                    #set the new name for the assessment
                    assessment.setName(request.form['txt%s%s' % (model.getIdentity(), assessment.getIdentity())])

                    #now save the actual assessment
                    assessmentStorageService.saveAssessment(assessment)


    elif request.form.has_key('btnDeleteAssessments') or request.form.has_key('btnLockAssessments') or request.form.has_key('btnUnlockAssessments'):
        #build a list of the selected assessments
        assessmentIds = []
        prefix = "chkAssessment"
        for formKey in request.form.keys():
            if prefix == formKey[0:len(prefix)]:
                assessmentId = formKey[len(prefix):]
                assessmentIds += [assessmentId]
        assessments = [assessmentStorageService.loadAssessment(assessmentId, model) for assessmentId in assessmentIds]

        if request.form.has_key('btnDeleteAssessments'):
            #------------------------------------#
            # DELETE ASSESSMENT(s)

            #get permission
            deleteAnyAssessmentPermission = securityService.getEffectivePermission("DeleteAnyAssessment", model.getIdentity(), user.getIdentity())

            #does the user have permission to delete assessment(s)?
            if deleteAnyAssessmentPermission is not None and deleteAnyAssessmentPermission.granted():

                #do we need to refund credits for assessment deletion?
                refundPermission = securityService.getEffectivePermission("RefundCreditsForAssessmentDeletion", model.getIdentity(), user.getIdentity())

                #delete each of the assessments
                deletionCount = 0
                for assessment in assessments:
                    #handle the 'onBeforeDeleteAssessment' event for the model
                    if model.isEventEnabled("onBeforeDeleteAssessment"):
                        model.getEnabledEvent("onBeforeDeleteAssessment").execute(assessment, user)

                    #delete the actual assessment
                    assessmentStorageService.deleteAssessment(assessment)

                    #refund the credit?
                    if refundPermission is not None and refundPermission.granted():            
                        
                        #get the credit transaction that was used to create the assessment (we will reverse that transaction)
                        creditTxn = assessment.getCreditTransactionIdentity()
                        
                        #if we have one... let's reverse it
                        if creditTxn is not None and len(creditTxn) > 0:
                            creditManagementService.reverseCredits(creditTxn, user.getIdentity(), "Refund for deleted assessment [%s]" % assessment.getName())

        if request.form.has_key('btnLockAssessments') or request.form.has_key('btnUnlockAssessments'):
            #------------------------------------#
            # UN/LOCK ASSESSMENT(s)

            #get permission
            changeAnyAssessmentLockStatePermission = securityService.getEffectivePermission('ChangeAnyAssessmentLockState', model.getIdentity(), user.getIdentity());

            #does the user have permission to lock/unlock assessment(s)?
            if changeAnyAssessmentLockStatePermission is not None and changeAnyAssessmentLockStatePermission.granted():
            
                #locking or unlocking?
                locking = request.form.has_key('btnLockAssessments')
            
                #lock/unlock the selected assessments
                for assessment in assessments:                 
                    #lock it?
                    if locking and not assessment.getIsLocked():
                        #handle the 'onBeforeLockAssessmentInAnyRepository' event for the model
                        if model.isEventEnabled("onBeforeLockAssessmentInAnyRepository"):
                            model.getEnabledEvent("onBeforeLockAssessmentInAnyRepository").execute(assessment, user)
                     
                        #lock
                        assessment.setIsLocked(locking)                               
                    
                    if not locking and assessment.getIsLocked():                    
                        #unlock
                        assessment.setIsLocked(locking)

                    #save the assessment
                    assessmentStorageService.saveAssessment(assessment)

    elif request.form.has_key('page'):
        #direct page navigation
        batchNr = int(request.form['page']) - 1

    else:
        #we've come from another page or refreshing
        pass

#----------------------------
#apply the current filter (if we have one)
if len(assessmentFilters) > 0 and currentAssessmentFilter is not None:

    #ensure that the current assessment filter is in the list and map (for displaying later)
    if not assessmentFilterMap.has_key(currentAssessmentFilter.getTitle()):
        assessmentFilterMap[currentAssessmentFilter.getTitle()] = currentAssessmentFilter
        assessmentFilters.append(currentAssessmentFilter)


    #==========================================================================
    # 20060530 johnm    Modify the expression if a lock status subfilter has
    #                   been provided
    #--------------------------------------------------------------------------
    if subFilter:
        expression = ['assessment', subFilter]
        if currentAssessmentFilter.getExpression():
            expression = ['all', currentAssessmentFilter.getExpression(), expression]
        currentAssessmentFilter.setExpression(expression)


    #==========================================================================
    # 20060630 johnm    Added the capability to filter based on creation and
    #                   modification date ranges. Fairly simple at the moment
    #--------------------------------------------------------------------------
    if displayCreationDateFilters:
        if createdAfterDate:
            expression = ["assessment","createdafter", createdAfterDate]
            if currentAssessmentFilter.getExpression():
                expression = ['all', currentAssessmentFilter.getExpression(), expression]
            currentAssessmentFilter.setExpression(expression)

        if createdBeforeDate:
            expression = ["assessment","createdbefore", createdBeforeDate]
            if currentAssessmentFilter.getExpression():
                expression = ['all', currentAssessmentFilter.getExpression(), expression]
            currentAssessmentFilter.setExpression(expression)


    if displayModificationDateFilters:
        if modifiedAfterDate:
            expression = ["assessment","modifiedafter", modifiedAfterDate]
            if currentAssessmentFilter.getExpression():
                expression = ['all', currentAssessmentFilter.getExpression(), expression]
            currentAssessmentFilter.setExpression(expression)

        if modifiedBeforeDate:
            expression = ["assessment","modifiedbefore", modifiedBeforeDate]
            if currentAssessmentFilter.getExpression():
                expression = ['all', currentAssessmentFilter.getExpression(), expression]
            currentAssessmentFilter.setExpression(expression)


    #determine the number of assessments we can scroll through for the current filter
    nrAssessments = assessmentStorageService.getNrAssessmentsSatisfyingFilter(currentAssessmentFilter, user)
  
    #ensure we are within the batch limits for the number of available assessments
    nrBatches = nrAssessments / batchSize
    if nrBatches * batchSize < nrAssessments:
        nrBatches = nrBatches + 1
    if batchNr < 0:
        batchNr = 0
    elif batchNr > nrBatches:
        batchNr = nrBatches - 1

    #fetch the assessments
    assessments = assessmentStorageService.getAssessmentsSatisfyingFilter(currentAssessmentFilter, user, batchNr, batchSize, sortBy)

    #TODO: determine the available multiple assessment reports for the current filter (need to include searching repositories.  currently only searchs the model)
    availableReports = model.getReports(user, "MultipleAssessmentReport")

    #remove reports that require a locked model (if the model is not locked)
    if not model.isLockedForEditing():
        availableReports = [report for report in availableReports if not report.isLockedModelRequired()]

    #set the current filter in the session (so we can use it for reports etc)
    session.set('currentAssessmentFilter', currentAssessmentFilter)

    #----------------------------
    #determine the primary repository in the current assessment filter
    dependencies = getDependencies(currentAssessmentFilter.getExpression(), model)

    #filter the dependencies by Repository
    repositories = [component for component in dependencies.values() if component.isInstanceOf('Repository')]

    #we use the first repository (if there is one)
    if len(repositories) > 0:
        repository = repositories[0]
    else: 
        repository = None

#no assessment filters or current assessment filter
else:
    nrAssessments = 0
    nrBatches = 0
    assessments = []
    availableReports = []
    dependencies = []
    repositories = []
    repository = None
    
#----------------------------
#determine the permissions applicable for the explorer 
#(also saves us doing the checks in the rendering page)
canEditAssessments = not 1
canDeleteAssessments = not 1
canChangeAssessmentLockStatus = not 1
canRenameAssessments = not 1

#are we exploring everything?
if hasExploreAllAssessmentsPermission:
    editAnyAssessmentPermission = securityService.getEffectivePermission('EditAnyAssessment', model.getIdentity(), user.getIdentity())
    canEditAssessments = editAnyAssessmentPermission is not None and editAnyAssessmentPermission.granted()
    
    changeAnyAssessmentLockStatePermission = securityService.getEffectivePermission('ChangeAnyAssessmentLockState', model.getIdentity(), user.getIdentity())
    canChangeAssessmentLockStatus = changeAnyAssessmentLockStatePermission is not None and changeAnyAssessmentLockStatePermission.granted()

    deleteAnyAssessmentPermission = securityService.getEffectivePermission('DeleteAnyAssessment', model.getIdentity(), user.getIdentity())
    canDeleteAssessments = deleteAnyAssessmentPermission is not None and deleteAnyAssessmentPermission.granted()

    renameAnyAssessmentPermission = securityService.getEffectivePermission('RenameAnyAssessment', model.getIdentity(), user.getIdentity())
    canRenameAssessments = renameAnyAssessmentPermission is not None and renameAnyAssessmentPermission.granted()
    
#are we exploring a repository?
elif repository is not None: 
    editRepositoryAssessmentsPermission = securityService.getEffectivePermission('EditRepositoryAssessments', repository.getIdentity(), user.getIdentity())
    canEditAssessments = editRepositoryAssessmentsPermission is not None and editRepositoryAssessmentsPermission.granted()

    renameRepositoryAssessmentsPermission = securityService.getEffectivePermission('RenameRepositoryAssessments', repository.getIdentity(), user.getIdentity())
    canRenameAssessments = renameRepositoryAssessmentsPermission is not None and renameRepositoryAssessmentsPermission.granted()

#we can't be here really
else:
    pass

#----------------------------
#set the report information in the request
request.set('assessmentFilters', assessmentFilters)
request.set('currentAssessmentFilter', currentAssessmentFilter)
request.set('repository', repository)
request.set('availableReports', availableReports)
request.set('sortBy', sortBy)
request.set('subFilter', subFilter)

request.set('displayCreationDateFilters', displayCreationDateFilters)
request.set('createdAfterDate', createdAfterDate)
request.set('createdBeforeDate', createdBeforeDate)

request.set('displayModificationDateFilters', displayModificationDateFilters)
request.set('modifiedAfterDate', modifiedAfterDate)
request.set('modifiedBeforeDate', modifiedBeforeDate)

request.set('assessments', assessments)
request.set('batchNr', batchNr)
request.set('nrBatches', nrBatches)
request.set('nrAssessments', nrAssessments)
request.set('model', model)

request.set('canEditAssessments', canEditAssessments)
request.set('canDeleteAssessments', canDeleteAssessments)
request.set('canChangeAssessmentLockStatus', canChangeAssessmentLockStatus)
request.set('canRenameAssessments', canRenameAssessments)

#----------------------------
#forward to the assessmentexplorer_modelreport.pt page
return context.assessmentexplorer_modelreport_render(context, request)
